//
//  IPDNSProtocol.h
//  INetworkPacketParser
//
//  Created by smallyou on 2019/3/12.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

/**
 Type of dns message
 
 - DNSMessageTypeQuery: query
 - DNSMessageTypeReply: reply
 */
typedef NS_ENUM(NSInteger, DNSMessageType) {
    DNSMessageTypeQuery = 0,
    DNSMessageTypeReply
};

/**
 Specify the type of query the message is carrying.
 
 @sa this field is setted by the creator of the query and copyied unchanged into the respones
 
 - DNSOperationCodeTypeQuery: a stand query
 - DNSOperationCodeTypeIQuery: an inverse query
 - DNSOperationCodeTypeStatus: a server status request
 - DNSOperationCodeTypeReserved: unused
 - DNSOperationCodeTypeNotify: specify the query type between master server and secondary servers
 - DNSOperationCodeTypeUpdate: it used in updated context
 */
typedef NS_ENUM(NSInteger, DNSOperationCodeType) {
    DNSOperationCodeTypeQuery = 0,
    DNSOperationCodeTypeIQuery,
    DNSOperationCodeTypeStatus,
    DNSOperationCodeTypeReserved,
    DNSOperationCodeTypeNotify,
    DNSOperationCodeTypeUpdate
};


/**
 Response code type
 @sa Set to zero in queries, then changed by the replying server in a response to convey
 the  results of processijng the query.This field is used to indicate if the query was answered
 successfully,or is some sort of error occurred
 
 - DNSResponseCodeTypeNoError: No error occurred
 - DNSResponseCodeTypeFormatError: The server was unable to respond to rhe query due to how it was constructed
 - DNSResponseCodeTypeServerFailure: The server was unable to respond to rhe query due to problem with the server itself
 - DNSResponseCodeTypeNameError: The name specified in the query does not exist in the domain.
 - DNSResponseCodeTypeNotImplement: The type of query received is not supported by the server
 - DNSResponseCodeTypeRefused: The server refused to process the query, generally for policy reasons.
 - DNSResponseCodeTypeYXDomain: A name exists when it should not
 - DNSResponseCodeTypeYXRRSet: A resource record set exists that should not
 - DNSResponseCodeTypeNXRRSet: A resouce record set tha should exist does not
 - DNSResponseCodeTypeNotAuth: The server receiving the query is not authoritative for the zone specified
 - DNSResponseCodeTypeNotZone: A name specified in the message is not within the zone specified in the message.
 */
typedef NS_ENUM(NSInteger, DNSResponseCodeType) {
    DNSResponseCodeTypeNoError = 0,
    DNSResponseCodeTypeFormatError,
    DNSResponseCodeTypeServerFailure,
    DNSResponseCodeTypeNameError,
    DNSResponseCodeTypeNotImplement,
    DNSResponseCodeTypeRefused,
    DNSResponseCodeTypeYXDomain,
    DNSResponseCodeTypeYXRRSet,
    DNSResponseCodeTypeNXRRSet,
    DNSResponseCodeTypeNotAuth,
    DNSResponseCodeTypeNotZone
};

/// DNS common query type
/// @sa https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
typedef NS_ENUM(NSInteger, IPDNSType) {
    IPDNSTypeA          = 1,                // host address
    IPDNSTypeNS         = 2,                // name server
    IPDNSTypeCNAME      = 5,                // alias
    IPDNSTypeSOA        = 6,                // start of authority
    IPDNSTypePTR        = 12,               // pointer
    IPDNSTypeHINFO      = 13,               // cpu & os
    IPDNSTypeMINFO      = 14,               // mailbox
    IPDNSTypeMX         = 15,               // mail exchange
    IPDNSTypeTXT        = 16                // arbitaray text
};

/// DNS common class type
/// @sa https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml
typedef NS_ENUM(NSInteger, IPDNSClass) {
    IPDNSClassReserved       = 0,                // reserved
    IPDNSClassInternet       = 1,                // INET/internet
    IPDNSClassUnassigned     = 2
};

/**
 DNS Query / Response header
 */
@interface IPDNSHeader : NSObject

/**
 Identifier: A 16-bit identification field generated by the device that creates the DNS query
 */
@property (nonatomic, assign) NSUInteger xid;

/**
 Query/Response type
 */
@property (nonatomic, assign) DNSMessageType qrType;

/**
 Operation code type
 */
@property (nonatomic, assign) DNSOperationCodeType opType;

/**
 Authoritative Answer Flag
 YES: indicate the answer server is authorizationed, otherwise is NO
 */
@property (nonatomic, assign) BOOL authoritativeAnswer;

/**
 Indicate the query whether be truncated
 */
@property (nonatomic, assign) BOOL truncation;

/**
 Indicate the query whether recursion query if the serve supported
 */
@property (nonatomic, assign) BOOL recursionDesired;

/**
 Set to YES or changed to NO in a response to indicate whether the server creating the response supports recursive queries. This can then be noted by the device that sent the query for future use.
 */
@property (nonatomic, assign) BOOL recursionAvailable;

/**
 Three reserved bits set to zero.
 @sa ununsed
 */
@property (nonatomic, assign) BOOL reservedZone;

/**
 Response code type
 */
@property (nonatomic, assign) DNSResponseCodeType responseCodeType;

/**
 Specified the number of questions in the querstion section of the message.
 */
@property (nonatomic, assign) NSInteger questionCount;

/**
 Specified the number of resouce records in the answer section of the message.
 */
@property (nonatomic, assign) NSInteger answerRecordCount;

/**
 Specifies th number of resouce records in the Authority section of the message.
 */
@property (nonatomic, assign) NSInteger authorityRecordCount;

/**
 Specifies the number of resouce records in the Additional section of the message.
 */
@property (nonatomic, assign) NSInteger additionalRecordCount;


@end

@interface IPDNSQuery : NSObject

/**
 The domain for which the query is sent.
 */
@property (nonatomic, copy) NSString *domainName;

/**
 dns type
 */
@property (nonatomic, assign) IPDNSType dnsType;

/**
 dns class
 */
@property (nonatomic, assign) IPDNSClass dnsClass;



@end

@interface IPDNSAnswer : NSObject

/**
 domainName field of the DNS Answer secion
 */
@property (nonatomic, copy) NSString *domainName;

/**
 DNS type
 */
@property (nonatomic, assign) IPDNSType dnsType;

/**
 DNS class
 */
@property (nonatomic, assign) IPDNSClass dnsClass;

/**
 DNS time to live
 */
@property (nonatomic, assign) NSInteger ttl;

/**
 Length of data field.
 */
@property (nonatomic, assign) NSInteger dataLength;

/**
 Data of answer, it's a various length
 */
@property (nonatomic, copy) NSString *data;

@end

NS_ASSUME_NONNULL_END
